﻿// 复习C++

#include <iostream>

using namespace std;


//// 运算符重载部分
//class Peo
//{
//private:
//	int m_age;
//public:
//	Peo(int age)
//	{
//		m_age = age;
//	}
//
//	// 前置++
//	Peo& operator++()
//	{
//		m_age++;
//		return *this;
//	}
//
//	// 后置++
//	Peo operator++(int)
//	{
//		// 可以
//		//Peo temp(this->m_age);
//
//		// 这个也行
//		Peo temp = *this;
//		m_age++;
//		return temp;
//	}
//
//
//
//	//// 尝试在类内实现 -------> 做不到输出自己的属性
//	//ostream& operator<<(ostream& cout)
//	//{
//	//	cout << this->m_age;
//	//	return cout;
//	//}
//	
//	// 全局函数
//	friend ostream& operator<<(ostream& cout, const Peo& peo);
//};
//
//
//// 全局函数
//// 无法在类内实现该运算符重载，因为要满足cout在左边，Peo在右边
//ostream& operator<<(ostream& cout, const Peo& peo)
//{
//	cout << peo.m_age;
//	return cout;
//}
//
//int main()
//{
//	// 左移运算符重载
//	//Peo p1(10);
//	//cout << p1 << endl;
//
//	// ++运算符重载
//	Peo p1(10);
//
//	// 前置++
//	++p1;
//	cout << p1 << endl;
//	// 后置++
//	p1++;
//
//	// 做不到，因为只能返回Peo，不能返回引用
//	//(p1++)++;
//
//	// 做不到，因为只能返回Peo，不能返回引用
//	++(p1++);
//	cout << p1 << endl;
//
//	return 0;
//}



// 继承部分

//class Fa
//{
//protected:
//	int m_age;
//public:
//	Fa()
//	{
//		m_age = 20;
//	}
//	static int m_height;
//};
//
//class Ma
//{
//protected:
//	int m_age;
//public:
//	Ma()
//	{
//		m_age = 18;
//	}
//};
//
//int Fa::m_height = 180;
//
//class Son : protected Fa, protected Ma
//{
//public:
//	Son(int age)
//	{
//		// 当继承两个类时，有同名时要加作用域
//		m_age = age;
//
//		// 说明可以用这种方式访问
//		// 因为是protected，所以在main函数内部无法访问，因此在这里访问
//		cout << Son::Fa::m_height << endl;
//	}
//
//	static int m_height;
//};
//
//int Son::m_height = 100;
//
//int main()
//{	
//	Fa fa;
//	Son son(10);
//	cout << fa.m_height << endl;
//	cout << Fa::m_height << endl;
//	cout << son.m_height << endl;
//	return 0;
//}


//// 菱形继承问题
//class Animal
//{
//public:
//	int m_age;
//};
//
//class Sheep : virtual public Animal
//{
//
//};
//
//class Tuo : virtual public Animal
//{
//
//};
//
//class SheepTuo : public Sheep, public Tuo
//{
//
//};
//
//void test01()
//{
//	SheepTuo st;
//
//	// 报错：不明确，要加定义域
//	//st.m_age = 10;
//	// 结构：Sheep和Tuo都有一个m_age
//	
//	// 用虚继承的方式解决，防止了同样的数据有两份，浪费资源，还会产生二义性
//	// 看结构：
//	// D:
//	// cd D:\tanjing118\the-second-semester-of-freshman-year\review_the_c++_basic\review_the_c++_basic
//	// dir
//	// cl /d1 reportSingleClassLayoutSheepTuo "review_the_c++_basic.cpp"
//	// 结构：Sheep和Tuo有同一个m_age
//	st.m_age = 10;
//	// 🐏、羊驼、驼的年龄都一样了
//}


//// 虚继承：地址晚绑定
//// 静态多态：运算符或者函数重载
//// 动态多态：虚函数 和 派生类
//class Animal
//{
//public:
//	// 不是虚函数时：两个都执行的是动物在说话
//	virtual void doSpeak()
//	{
//		cout << "动物在说话" << endl;
//	}
//};
//
//class Cat : public Animal
//{
//public:
//	void doSpeak()
//	{
//		cout << "小猫在说话" << endl;
//	}
//};
//
//void doSpeak(Animal& animal)
//{
//	animal.doSpeak();
//}
//
//void test02()
//{
//	Cat cat;
//	doSpeak(cat);
//
//	Animal animal;
//	doSpeak(animal);
//}

//// 默认参数后面的参数一定要传参
//int add(int a, int b = 10, int c)
//{
//	return a + b;
//}
//
//int print(int a, int)
//{
//	return a;
//}
//
//void test03()
//{
//	// 默认参数位置可以不传参
//	cout << add(1) << endl;
//
//	// 占位参数必须传参
//	cout << print(1) << endl;
//}


//class Animal
//{
//public:
//	Animal()
//	{
//		cout << "Animal的构造函数调用" << endl;
//	}
//	// 不是虚函数时：两个都执行的是动物在说话
//	virtual void doSpeak()
//	{
//		cout << "动物在说话" << endl;
//	}
//	// 没有virtual时delete animal时不会调用子类的析构函数，会引起内存泄漏
//	virtual ~Animal()
//	{
//		cout << "Animal的析构函数调用" << endl;
//	}
//};
//
//class Cat : public Animal
//{
//public:
//	Cat()
//	{
//		cout << "Cat的构造函数调用" << endl;
//	}
//	void doSpeak()
//	{
//		cout << "小猫在说话" << endl;
//	}
//	~Cat()
//	{
//		cout << "Cat的析构函数调用" << endl;
//	}
//};
//
//
//void test04()
//{
//	Animal* animal = new Cat;
//	delete animal;
//}
//
//int main()
//{
//	// 菱形继承的问题
//	//test01();
//
//	// 虚继承
//	//test02();
//
//	// 占位参数 和 默认参数
//	// 占位参数：为了后面需要增加参数时用，占位参数位置   必须传参
//	// 默认参数：默认参数位置可以不传参，但  
//	// 1、默认参数后面所有参数也要是默认参数
//	// 2、默认参数的函数  声明  和  实现  只能有一个 设置了默认值
//	//test03();
//
//	// 父类释放时不会调用子类的析构函数，可能造成内存泄漏
//	test04();
//	return 0;
//}


// 模板

//template <typename NameType, typename AgeType>
//class Peo
//{
//private:
//	NameType m_name;
//	AgeType m_age;
//public:
//	Peo(NameType name, AgeType age)
//	{
//		m_name = name;
//		m_age = age;
//
//		// 打印 系统猜测我们的模板的数据类型
//		cout << typeid(NameType).name() << endl;
//		cout << typeid(AgeType).name() << endl;
//	}
//	Peo(AgeType age)
//	{
//		m_age = age;
//
//		// 打印 系统猜测我们的模板的数据类型
//		cout << typeid(AgeType).name() << endl;
//	}
//};
//
//template <typename NameType, typename AgeType>
//void test01()
//{
//	// 可以
//	//Peo<string, int> peo("张三", 18);
//
//	// 不可
//	//Peo peo(18);
//
//	// 可以
//	Peo<NameType, AgeType> peo("张三", 18);
//}

//class Peo1
//{
//public:
//	void func1()
//	{
//		cout << "这是func1" << endl;
//	}
//};
//
//class Peo2
//{
//public:
//	void func2()
//	{
//		cout << "这是func2" << endl;
//	}
//};
//
//template <typename T>
//class Test
//{
//public:
//	T obj;
//
//	Test()
//	{
//		obj.func1();
//		obj.func2();
//
//		cout << typeid(T).name() << endl;
//	}
//};
//
//void test02()
//{
//	// 当没有这一行时，能过
//	// 加了这一行后，显示：func2不是Peo1的成员
//	// ----------------> 类模板中的成员函数并不是一开始就闯将，而是调用函数时才创建
//	Test<Peo1> test;
//}


//int main()
//{
//	// 测试类模板可不可以根据传入的参数推出类型
//	// 不太行
//	// test01()
//
//	//test01<string, int>();
//
//	// 测试类模板中的成员函数的创建时机
//	//test02();
//
//	return 0;
//}



// STL
// 注意各个容器的操作前提，如：出队，出栈等操作需要满足 -- 容器中有元素

// 单端数组
#include <vector>

// 双端数组
#include <deque>

// 栈
#include <stack>

// 队列
#include <queue>

// 链表
#include <list>

// set
#include <set>

// map
#include <map>
#include <unordered_map>
//// 没有这个头文件
//#include <multimap>

//void test01()
//{
//	//vector<int> vec(10, 10);// 10个值为10的元素
//
//	////// insert:
//	////// 1、insert(const_interator pos, ele)
//	////// 2、insert(const_interator pos, int count, ele)
//	////vec.insert(vec.begin() + 1, 2);
//	////cout << vec.size() << endl;
//
//	////// erase:
//	////// 1、erase(const_interator pos)
//	////// 2、erase(const_interator start, const_interator end)
//
//	////int* p = &vec[0];
//	////vec.erase(vec.begin(), vec.end());
//	////cout << vec.size() << endl;
//
//	////// 以下为非法访问，但仍然可以输出
//	////cout << *p << endl;
//	////cout << *(p + 1) << endl;
//	////cout << *(p + 11) << endl;
//	////cout << *(p + 100) << endl;
//
//	////// 以下为非法访问，但仍然可以修改
//	////*p = 100;
//	////cout << *p << endl;
//
//	////// at(int idx)
//	////// 返回idx所指数据
//	////cout << vec.at(1) << endl;
//
//	//// front:返回容器第一个   元素
//	//cout << vec.front() << endl;
//
//	//// back:返回容器最后一个   元素
//	//cout << vec.back() << endl;
//	
//
//	//for (int i = 0; i < vec.size()/*这样子更灵活，但是最好不要每次循环的时候算一遍，可以在循环前面定义一个变量存容器的大小*/; i++)
//	//	cout << vec[i] << " ";
//	//cout << endl;
//
//	// swap(vec)：将vec与本身的元素互换
//	//vector<int>vec1(10, 1);
//	//vector<int>vec2(10, 2);
//	//
//	//vec1.swap(vec2);
//
//	//cout << "vec1中的元素：";
//	//for (int i = 0; i < vec1.size(); i++)
//	//	cout << vec1[i] << " ";
//	//cout << endl;
//
//	//cout << "vec2中的元素：";
//	//for (int i = 0; i < vec1.size(); i++)
//	//	cout << vec2[i] << " ";
//	//cout << endl;
//
//	//// swap的两个容器不同没有影响
//	//vector<int>vec1(5, 1);
//	//vector<int>vec2(10, 2);
//
//	//vec1.swap(vec2);
//
//	//cout << "vec1中的元素：";
//	//for (int i = 0; i < vec1.size(); i++)
//	//	cout << vec1[i] << " ";
//	//cout << endl;
//
//	//cout << "vec2中的元素：";
//	//for (int i = 0; i < vec2.size(); i++)
//	//	cout << vec2[i] << " ";
//	//cout << endl;
//
//
//	// 测试resize后是否仍然可以访问  resize前  合法，resize后  不合法的地址空间
//	// 测试结果：不可以，会崩溃
//	//vector<int> vec(10, 10);
//	//vec.resize(5);
//	//cout << vec[5] << endl;
//
//	// 尝试用指针访问
//	// 可以
//	//vector<int> vec(10, 10);
//	//int* p = &vec[0];
//	//vec.resize(5);
//	//cout << *(p + 5) << endl;
//
//	/*
//	提问：
//	 vector<int> vec(10, 10);
//    int* p = &vec[0];
//    vec.resize(5);
//    cout << *(p + 5) << endl;
//	我在复习容器的时候就在想，我如果更改了容器，
//	我是不是仍然可以通过不合法的手段来获取数据，我就写了这种代码，
//	发现虽然现在这个地方已经不合法了，但是我仍然可以访问甚至修改数据，
//	这种危险行为应该怎么避免，比如恶意代码 -------------> 无法避免
//	*/
//
//	// 安全做法（避免非法访问）
//	//vector<int> vec(10, 10);
//	//auto it = vec.begin(); // 使用迭代器而不是指针
//	//vec.resize(5);
//	//cout << *(it + 5) << endl; // 这里会产生编译错误，迭代器不支持随机访问
//
//	//// swap的用途：避免资源浪费
//	//// resize:只会改变容器大小，但不会改变容器容量 —— 一开始大小和容量都是10， resize(5)后：大小为5，但容量仍然为10
//	//// 这种情况可以用swap的方式优化
//	//vector<int>vec(10);
//	//vector<int>(vec).swap(vec);
//	//// vector<int>(vec):创建一个匿名对象，该对象由vec初始化
//	//// .swap(vec);调换两者，size属性也会调换
//	//// 而匿名对象到下一条语句就自动销毁
//	//cout << vec.size() << endl;
//	//cout << vec.capacity() << endl;
//
//
//	// reserve:预留、保留
//	// 避免多次扩展
// 
// 
	
	// reverse（反转）
	//vector<int>vec(10);
	//for (int i = 0; i < vec.size(); i++)
	//	vec[i] = i;

	////reverse(vec.begin(), vec.end());

	//for (int i = 0; i < vec.size(); i++)
	//	cout << vec[i] << " ";
	//cout << endl;

	//vector<int>vec;
	//vec.front();
	//vec.back();

//}

//void test02()
//{
//	//vector<int>vec(10, 10);
//	//deque<int> deq(vec.begin(), vec.end());
//
//	//int arr[10] = { 10, 10, 10, 10, 10, 10, 10, 10, 10 };
//	//deque<int> deq(arr, arr + 9);
//
//	//deque<int>deq(9);
//
//	//// 无序
//	//deq[0] = 10;
//	//deq[1] = 104;
//	//deq[3] = 141;
//	//deq[2] = 11;
//	//deq[4] = 43;
//	//deq[5] = 0;
//	//deq[6] = 4;
//	//sort(deq.front(), deq.back());// 注意不是begin和end
//
//	// 无序
//	deque<int> deq;
//	deq.push_back(10);
//	deq.push_back(20);
//	deq.push_back(112);
//	deq.push_back(13);
//	deq.push_back(113);
//	deq.push_back(30);
//	deq.push_back(1313);
//
//
//	for (int i = 0; i < deq.size(); i++)
//		cout << deq[i] << " ";
//	cout << endl;
//}

//void test03()
//{
//	// 栈不允许遍历操作，只有栈顶能查看
//	stack<int>st;
//
//	//st.push(10);
//	//st.top() = 11;
//
//	//// 栈不允许遍历操作，只有栈顶能查看
//	//st.push(20);
//	//st.top() - 1 = 21;
//
//	cout << st.top() << endl;
//}


//void test04()
//{
//	// queue：队列，也不支持随机访问
//	// 是front和back 
//  // 是push和pop，不是push_back和pop_back
	//queue<int>que;
	//que.push(1);
	//que.push(0);
	
	// 错误写法，因为que不支持随机访问
	// sort(que.begin(), que.end());
	// 只能将元素放入可随机访问的容器里才可  或者  优先队列
//}

//void test05()
//{
//	// list，链表
//	// STL中的链表是双向循环链表
//	// 是front和back
//	list<int> l;
//	l.push_front(1);
//	l.push_front(21);
//	l.push_front(31);
//	l.push_front(10);
//
//	for (auto it : l)
//		cout << it << " ";
//	cout << endl;
//
//	//// 不可这样子访问，不支持随机访问
//	//for (list::iterator it = l.front(); it != l.back(); it++)
//	//	cout << *it << endl;
//
//	// 双向迭代器，只能向前向后
//	// 只能it++,或者it--
//	// 不能it + 1，因为不可以随机访问 
//
//	// 不能sort(l.begin(), l.end());因为他无序，且不支持随机访问
//	// 但是提供了相应的算法
//	//l.sort();
//	// 若想降序，则：l.sort(cmp);
//
//	reverse(l.begin(), l.end());
//	for (auto it : l)
//		cout << it << " ";
//	cout << endl;
//
// // 可以remove(elem)
//}

//void test06()
//{
//	// 可以erase(elem)
//
//	// multiset：可有重复元素
//	// multiset<int> set;
//	// multiset没有这个头文件，直接包含在set头文件里了
//
//	//multiset<int>mset;
//	//mset.insert(1);
//	//mset.insert(21);
//	//mset.insert(1);
//	//mset.insert(12);
//	//mset.insert(113);
//
//
//	// set没有push等操作，只有insert
//	// set没有重复元素
//	// 不要容器名 = 变量名，不然报错都看不懂（白眼）
//	set<int>sset;
//
//	// pair<iterator, bool> insert(value_type&& _Val)
//	// 会返回插入结果，表示是否插入成功，可以通过返回值的second查看是否插入成功
//	//set.insert(1);
//	//set.insert(21);
//	//set.insert(1);
//	//set.insert(12);
//	//set.insert(113);
//	//// find(ket)，找到了就返回该键值的迭代器，没找到则返回end
//	//auto it = set.find(1);
//	//cout << *it << endl;
//
//	//// count(key)，统计key的个数
//	//// 注意：只有0 和 1 两种结果，因为set没有重复元素
//	//cout << "set.count(1) = " << set.count(1) << endl;
//
//	//cout << "mset.count(1) = " << mset.count(1) << endl;
//
//	//// 会显示第一次成功，第二次失败
//	//pair<set<int>::iterator, bool> pa = sset.insert(100);
//
//	//if (pa.second)
//	//{
//	//	cout << "插入成功" << endl;
//	//}
//	//else
//	//{
//	//	cout << "插入失败" << endl;
//	//}
//
//	//pa = sset.insert(100);
//
//	//if (pa.second)
//	//{
//	//	cout << "插入成功" << endl;
//	//}
//	//else
//	//{
//	//	cout << "插入失败" << endl;
//	//}
//	
//	// 若要降序排列，则需要  在  set建立前  写好仿函数（重载小括号）
//	// 用set<int, 类名>的方式定义 ----------->!!!!! 注意：后续遍历的时候也要是这种类型
//}


//void test07()
//{
//	/*
//	* https://blog.csdn.net/2301_79293429/article/details/135948574
//	使用 <map> 来声明和操作   有序  的键-值对。
//	使用 <unordered_map> 来声明和操作   无序   的键-值对，通过哈希表实现快速查找。
//	使用 <multimap> 来声明和操作允许键    重复的   有序  键-值对容器。------------ 注意，没有multimap和multiset这两个头文件
//	*/
//
//	map<int, int> mp;
//	// map的元素都是pair键值对
//	mp.insert({ 1, 2 });
//	mp.insert({ 2, 1 });
//	mp.insert({ 3, 1 });
//	mp.insert({ 21, 4 });
//	mp.insert({ 43, 13 });
//	mp.insert({ 11, 232});
//
//	cout << "size = " << mp.size() << endl;
//
//	// 会打印 0 ，因为没有mp[5]，它就会自动创建一个键值为5，val为0的数据
//	cout << mp[5] << endl;
//
//	cout << "size = " << mp.size() << endl;
//
//	cout << "mp[3](该键值存在) = " << mp[3] << endl;
//
//	// 会删除 键值 为1的数据
//	mp.erase(1);
//	for (auto it : mp)
//	{
//		cout << "key = " << it.first << " value = " << it.second << endl;
//	}
//
//	//vector<int> vec;
//	//// 是删除迭代器，不是删除  值
//	//vec.erase(vec.begin());
//}
//
//int main()
//{
//	//// vector的相关操作
//	//test01();
//
//	// deque，双端数组的相关操作
//	//test02();
//
//	// stack
//	//test03();
//	
//	// queue
//	//test04();
//	
//	// list队列
//	// test05();
//
//	// set
//	// set自动排序
//	// test06();
//
//	// map
//	// map自动根据键值排序
//	test07();
//	return 0;
//}


#include <algorithm>
#include <functional>
#include <numeric>


void test01()
{
	int arr[10] = { 1, 2, 1, 23, 32, 421, 1, 391, 31, 31 };

	cout << "原数组：";
	for (int i = 0; i < sizeof arr / sizeof(int); i++)
		cout << arr[i] << " ";
	cout << endl;


	// 替换迭代器的val值
	replace(arr, arr + 9, 1, 3);

	// 查找第一个相邻相同元素
	auto it = adjacent_find(arr, arr + 9);
	cout << "第一个相邻相同元素为： " <<  *it << endl;

	// 洗牌 —— 记得随机数种子
	random_shuffle(arr, arr + 9);


	for (int i = 0; i < sizeof arr / sizeof(int); i++)
		cout << arr[i] << " ";
	cout << endl;
}

int main()
{
	// 算法
	test01();
	return 0;
}